package com.l2qq.admin.permission; /**
 * 本项目采用《JFinal 俱乐部授权协议》，保护知识产权，就是在保护我们自己身处的行业。
 * 
 * Copyright (c) 2011-2021, jfinal.com
 */

import com.jfinal.core.Action;
import com.jfinal.core.JFinal;
import com.jfinal.core.Path;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.l2qq.common.model.Permission;
import com.l2qq.common.model.Role;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限管理业务
 */
public class PermissionAdminService {
	
	private static int pageSize = 25;
	private Permission permissionDao = new Permission().dao();

	// 一键同步功能需要排除掉的 actionKey
	private Set<String> excludedActionKey = buildExcludedActionKey();

	/**
	 * 增强版同步功能 - 保留权限分组、权限注解和权限依赖
	 */
	public Ret syncEnhanced() {
		int counter = 0;
		int cancelCount = 0; // 记录取消的权限数量
		// 1. 扫描所有控制器类
		Map<Class<?>, ControllerMeta> controllerMetaMap = scanControllers("com.l2qq");
		Set<String> existingControllers = controllerMetaMap.keySet().stream()
				.map(Class::getName)
				.collect(Collectors.toSet());

		// 2. 处理每个控制器的方法
		for (Map.Entry<Class<?>, ControllerMeta> entry : controllerMetaMap.entrySet()) {
			Class<?> controllerClass = entry.getKey();
			ControllerMeta meta = entry.getValue();

			for (Method method : controllerClass.getDeclaredMethods()) {
				if (method.isAnnotationPresent(PermissionAuth.class)) {
					PermissionAuth permAnnotation = method.getAnnotation(PermissionAuth.class);

					// 3. 创建权限元数据
					PermissionMeta permMeta = new PermissionMeta(
							permAnnotation.key(),
							permAnnotation.value(),
							meta.getGroup(),
							permAnnotation.category(),
							controllerClass.getName(),
							method.getName(),
							permAnnotation.remark()
					);

					// 4. 处理依赖关系
					if (method.isAnnotationPresent(PermissionDependency.class)) {
						PermissionDependency dep = method.getAnnotation(PermissionDependency.class);
						for (String depKey : dep.value()) {
							permMeta.addDependency(depKey);
						}
					}

					// 5. 同步到数据库
					if (syncPermissionToDatabase(permMeta)) {
						counter++;
					}
				}
			}
		}
		// 3. 标记已不存在的控制器权限为取消状态
		List<Permission> allPermissions = permissionDao.findAll();
		for (Permission p : allPermissions) {
			if (!existingControllers.contains(p.getController())) {
				if (!p.getIsCancel()) {
					p.setIsCancel(true);
					if (p.update()) {
						cancelCount++;
					}
				}
			}
		}
		// 返回结果包含更新和取消的权限数量
		if (counter > 0 || cancelCount > 0) {
			return Ret.ok("msg", "同步成功")
					.set("更新数量：", counter)
					.set("接口取消数量：", cancelCount);
		} else {
			return Ret.ok("msg", "权限已是最新状态");
		}
	}

	/**
	 * 扫描控制器类并提取元数据
	 */
	private Map<Class<?>, ControllerMeta> scanControllers(String basePackage) {
		Map<Class<?>, ControllerMeta> result = new HashMap<>();

		try {
			// 获取所有 action keys
			List<String> allActionKeys = JFinal.me().getAllActionKeys();
			Set<Class<?>> processedControllers = new HashSet<>();

			for (String actionKey : allActionKeys) {
				// 获取对应的 Action 对象
				String[] urlPara = new String[1];
				Action action = JFinal.me().getAction(actionKey, urlPara);

				if (action == null) {
					continue; // 跳过无效的 actionKey
				}

				Class<?> controllerClass = action.getControllerClass();

				// 过滤指定包下的控制器
				if (!controllerClass.getName().startsWith(basePackage)) {
					continue;
				}

				// 避免重复处理同一个控制器
				if (processedControllers.contains(controllerClass)) {
					continue;
				}
				processedControllers.add(controllerClass);

				ControllerMeta meta = new ControllerMeta();

				// 提取分组信息
				if (controllerClass.isAnnotationPresent(PermissionGroup.class)) {
					PermissionGroup group = controllerClass.getAnnotation(PermissionGroup.class);
					meta.setGroup(group.value());
				} else {
					meta.setGroup(controllerClass.getSimpleName());
				}

				// 提取路由前缀
				if (controllerClass.isAnnotationPresent(Path.class)) {
					Path path = controllerClass.getAnnotation(Path.class);
					meta.setRoutePrefix(path.value());
				}

				result.put(controllerClass, meta);
			}
		} catch (Exception e) {
			throw new RuntimeException("控制器扫描失败", e);
		}

		return result;
	}


	private void processDependencies(int permissionId, Set<String> dependencyKeys) {
		// 先删除旧依赖关系
		Db.delete("DELETE FROM permission_dependency WHERE permission_id = ?", permissionId);
        if (dependencyKeys == null || dependencyKeys.isEmpty()) {
            return;
        }
		// 添加新依赖关系
		for (String key : dependencyKeys) {
			// 查找依赖权限的ID
			Permission dep = permissionDao.findFirst("SELECT id FROM permission WHERE perm_key = ?", key);
			if (dep != null) {
				Record dependency = new Record();
				dependency.set("permission_id", permissionId);
				dependency.set("dependency_id", dep.getId());
				dependency.set("created_at", new Date());
				Db.save("permission_dependency", dependency);
			}
		}
	}

	/**
	 * 将权限元数据同步到数据库
	 */
	private boolean syncPermissionToDatabase(PermissionMeta meta) {
		// 根据key查找现有权限
		Permission permission = permissionDao.findFirst("SELECT * FROM permission WHERE perm_key = ?", meta.getKey());
		boolean updated = false;
		if (permission == null) {
			// 创建新权限
			permission = new Permission();
			permission.setPermKey(meta.getKey());
			permission.setName(meta.getName());
			permission.setPermGroup(meta.getGroup());
			permission.setCategory(meta.getCategory());
			permission.setController(meta.getController());
			permission.setActionKey(meta.getMethod());
			permission.setRemark(meta.getRemark());
            permission.save();
			processDependencies(permission.getId(), meta.getDependencies());
			return true;
		} else {

			// 更新现有权限
			if (!Objects.equals(permission.getName(), meta.getName())) {
				permission.setName(meta.getName());
				updated = true;
			}
			if (!Objects.equals(permission.getPermGroup(), meta.getGroup())) {
				permission.setPermGroup(meta.getGroup());
				updated = true;
			}
			if (!Objects.equals(permission.getCategory(), meta.getCategory())) {
				permission.setCategory(meta.getCategory());
				updated = true;
			}
			if (!Objects.equals(permission.getController(), meta.getController())) {
				permission.setController(meta.getController());
				updated = true;
			}
			if (!Objects.equals(permission.getActionKey(), meta.getMethod())) {
				permission.setActionKey(meta.getMethod());
				updated = true;
			}
			if (!Objects.equals(permission.getRemark(), meta.getRemark())) {
				permission.setRemark(meta.getRemark());
				updated = true;
			}
			if (updated) {
				permission.setUpdatedAt(new Date());
			}
            //直接更新，如果处理iscannel问题
            permission.setIsCancel(false);
            permission.update();
			// 更新依赖关系
			processDependencies(permission.getId(), meta.getDependencies());
			return updated;
		}
	}



	/**
	 * 一键同步功能需要排除的 actionKey，在本方法中添加
	 */
	private Set<String> buildExcludedActionKey() {
		Set<String> ret = new HashSet<String>();
		/**
		 * 以下添加的 "/admin/captcha" 所对应的 action 没有拦截器，已经被排除掉，
		 * 无需在此添加，在此添加仅为了演示功能
		 */
		ret.add("/admin/captcha");
		return ret;
	}

	public Page<Permission> paginate(int pageNum) {
		return permissionDao.paginate(pageNum, pageSize, "select *", "from permission order by action_key asc");
	}

	/**
	 * 搜索
	 */
	public Page<Permission> search(String key, int pageNumber) {
		String sql = "select * from permission where action_key like concat('%', #para(0), '%') order by action_key asc";
		return permissionDao.templateByString(sql, key).paginate(pageNumber, pageSize);
	}

	/**
	 * 在已被移除的 permission 中 put 进去一个 removed 值为 true 的标记，便于在界面显示不同的样式
	 * @return 存在被删除的 actionKey 时返回 true，否则返回 false
	 */
	public boolean markRemovedActionKey(Page<Permission> permissionPage) {
		boolean ret = false;

		for (Permission p : permissionPage.getList()) {
			String actionKey = p.getActionKey();

			String[] urlPara = new String[1];
			Action action = JFinal.me().getAction(actionKey, urlPara);
			if (action == null || ! actionKey.equals(action.getActionKey())) {
				p.put("removed", true);
				ret = true;
			}
		}

		return ret;
	}

	/**
	 * 替换控制器前缀，界面显示时更加美观
	 *
	 * 例子:
	 *    replaceControllerPrefix(page, "com.jfinal.admin.", "...");
	 *    以上例子将 "com.jfinal.admin." 这一长串前缀替换成 "..."，显示更美观
	 */
	public void replaceControllerPrefix(Page<Permission> permissionPage, String replaceTarget, String replacement) {
		for (Permission p : permissionPage.getList()) {
			String c = p.getController().replace(replaceTarget, replacement);
			p.setController(c);
		}
	}

	/**
	 * 同步 permission
	 * 获取后台管理所有 actionKey 以及 controller，将数据自动写入 permission 表
	 * 随着开发过程的前行，可以动态进行同步添加新的 permission 数据
	 */
	public Ret sync() {
		int counter = 0;
		List<String> allActionKeys = JFinal.me().getAllActionKeys();
		List<Permission> allPermissions = permissionDao.findAll();

		for (String actionKey : allActionKeys) {
			// 只处理后台管理 action，其它跳过
			if ( !actionKey.startsWith("/admin") ) {
				continue ;
			}
			// 跳过需要排除的 actionKey
			if (excludedActionKey.contains(actionKey)) {
				continue ;
			}


			String[] urlPara = new String[1];
			Action action = JFinal.me().getAction(actionKey, urlPara);
			// 没有拦截器的 action 任何人都能访问，需要排除掉，例如:"/admin/login" "/admin/logout"
			if (action == null || action.getInterceptors().length == 0 || action.getActionKey().startsWith("/admin/test")) {
				continue ;
			}

			String controller = action.getControllerClass().getName();



			Map<String, Permission> permissionMap = allPermissions.stream()
					.collect(Collectors.toMap(
							p -> generateKey(p.getActionKey(), p.getController()),
							p -> p,
							(existing, replacement) -> existing // 如果有重复键，保留已存在的记录（模拟limit 1行为）
					));


// 处理当前权限项
			String currentKey = generateKey(actionKey, controller);
			Permission permission = permissionMap.get(currentKey);

			if (permission == null) {
				// 创建新权限
				permission = new Permission();
				permission.setActionKey(actionKey);
				permission.setController(controller);

				// 保存到数据库并回填生成的主键（假设save()方法会更新对象ID）
				if (permission.remove("id").save()) {
					permissionMap.put(currentKey, permission); // 更新缓存
					counter++;
				}
			} else {
				// 仅当remark为空时更新
				if (StrKit.isBlank(permission.getRemark())) {
					if (permission.update()) {
						counter++;
					}
				}
			}


		}

		if (counter == 0) {
			return Ret.ok("msg", "权限已经是最新状态，无需更新");
		} else {
			return Ret.ok("msg", "权限更新成功，共更新权限数 : " + counter);
		}
	}

	// 生成唯一键的工具方法
	private static String generateKey(String actionKey, String controller) {
		return actionKey + "::" + controller; // 使用双冒号降低键冲突概率
	}


	public Permission findById(int id) {
		return permissionDao.findById(id);
	}

	public List<Permission> getAllPermissions(Role role) {
		return permissionDao.find("select *,case when permission_id is null then false else true end as assigned  from( select * from( select * from permission where is_show = true) as a LEFT JOIN (SELECT * FROM role_permission WHERE role_id = ? ) as b on a.id = b.permission_id ) as a order by controller asc",role.getId());
	}

	public Ret update(Permission permission) {
		permission.keep("id", "remark");	// 暂时只允许更新 remark
		permission.update();
		return Ret.ok("msg", "更新成功");
	}

	/**
	 * 如果某个 action 已经删掉，或者改了名称，可以使用该方法删除
	 */
	public Ret delete(final int permissionId) {
		Db.tx(() -> {
			Db.delete("delete from role_permission where permission_id = ?", permissionId);
			permissionDao.deleteById(permissionId);
			return true;
		});

		return Ret.ok("msg", "权限删除成功");
	}
}

